package du.myseckill.controller;

import du.myseckill.dto.Exposer;
import du.myseckill.dto.SeckillExcecution;
import du.myseckill.exception.ServerException;
import du.myseckill.pojo.Goods;
import du.myseckill.service.GoodsService;
import du.myseckill.service.Impl.GoodsServiceImpl;
import du.myseckill.vo.SecKillResult;
import io.lettuce.core.dynamic.annotation.Param;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;

@Slf4j
@RequestMapping("/secKill")
@Controller
public class GoodsController {
    @Autowired
    private GoodsServiceImpl goodsService;

    @RequestMapping("/goodsList")
    public String getGoodsList(Model model) {
        List<Goods> goodsList = goodsService.getGoodsList();
        model.addAttribute("list", goodsList);
        return "list";
    }

    @RequestMapping("/{goodsId}/goods")
    public String getGoods(@PathVariable("goodsId") long goodsId, Model model) {
        Goods goodsById = goodsService.getGoodsById(goodsId);
        if (goodsById == null) {
            return "redirect:/goodsList";
        }
        model.addAttribute("goods", goodsById);
        return "detail";
    }

    /**
     * 暴露秒杀接口
     * @param goodsId
     * @param model
     * @return
     */
    @RequestMapping(value = "/{goodsId}/exposer", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<Exposer> exposer(@PathVariable("goodsId") Long goodsId, Model model) {
        SecKillResult<Exposer> result;
        try {
            Exposer exposer = goodsService.exposeSeckillUrl(goodsId);
            result = new SecKillResult<Exposer>(true, exposer);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result = new SecKillResult<Exposer>(false, e.getMessage());
        }
        return result;
    }

    /**
     * 基于AOP加锁的秒杀操作
     * @param goodsId
     * @param useId
     * @param phone
     * @param md5
     * @param model
     * @return
     * @throws ServerException
     */
    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/executionAOP", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> executeAOP(@PathVariable("goodsId") Long goodsId,
                                                    @PathVariable("userId") long useId,
                                                    @CookieValue(value = "userPhone", required = false) Long phone,
                                                    @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKillAOPLock(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }
    /**
     * 基于数据库悲观锁的秒杀操作
     * @param goodsId
     * @param useId
     * @param phone
     * @param md5
     * @param model
     * @return
     * @throws ServerException
     */
    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/execution", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> execute(@PathVariable("goodsId") Long goodsId,
                                                    @PathVariable("userId") long useId,
                                                    @CookieValue(value = "userPhone", required = false) Long phone,
                                                    @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKill(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }

    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/executionDBP", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> executeDBPLock(@PathVariable("goodsId") Long goodsId,
                                                           @PathVariable("userId") long useId,
                                                           @CookieValue(value = "userPhone", required = false) Long phone,
                                                           @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKillDBPLock(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }

    /**
     * 基于数据库乐观锁的秒杀
     * @param goodsId
     * @param useId
     * @param phone
     * @param md5
     * @param model
     * @return
     * @throws ServerException
     */
    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/executionDBO", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> executeDBOLock(@PathVariable("goodsId") Long goodsId,
                                                           @PathVariable("userId") long useId,
                                                           @CookieValue(value = "userPhone", required = false) Long phone,
                                                           @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKillDBOLock(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }


    /**
     * 基于分布式锁的秒杀操作
     * @param goodsId
     * @param useId
     * @param phone
     * @param md5
     * @param model
     * @return
     * @throws ServerException
     */
    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/executeRedisLock", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> executeRedisLock(@PathVariable("goodsId") Long goodsId,
                                                           @PathVariable("userId") long useId,
                                                           @CookieValue(value = "userPhone", required = false) Long phone,
                                                           @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKillAOPRedisLock(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }

    /**
     * 利用消息队列和缓存进行限流的秒杀操作
     * @param goodsId
     * @param useId
     * @param phone
     * @param md5
     * @param model
     * @return
     * @throws ServerException
     */
    @RequestMapping(value = "/{goodsId}/{md5}/{userId}/executeMQ", method = RequestMethod.POST,
            produces = {"application/json;character=utf-8"})
    @ResponseBody
    public SecKillResult<SeckillExcecution> executeMQ(@PathVariable("goodsId") Long goodsId,
                                                             @PathVariable("userId") long useId,
                                                             @CookieValue(value = "userPhone", required = false) Long phone,
                                                             @PathVariable("md5") String md5, Model model) throws ServerException {
        SeckillExcecution seckillExcecution = goodsService.executeSecKillByMQ(goodsId, useId, phone, md5);
        return new SecKillResult(true, seckillExcecution);
    }
    @RequestMapping(value = "/time/now" ,method = RequestMethod.GET)
    @ResponseBody
    public SecKillResult<Long> time(){
        Date date = new Date();
        return new SecKillResult<Long>(true,date.getTime());
    }
}